
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 *版权所有2002-2018原创作者。
 *
 *根据Apache许可证2.0版许可（“许可证”）；
 *除非符合许可证的规定，否则您不得使用此文件。
 *您可以在以下网址获取许可证副本：
 *
 *https://www.apache.org/licenses/LICENSE-2.0
 *
 *除非适用法律要求或书面同意，软件
 *根据许可证进行的分发是在“按原样”的基础上进行的，
 *无任何明示或暗示的保证或条件。
 *有关管理权限的特定语言，请参阅许可证和
 *许可证下的限制。
 */

package org.springframework.scheduling.concurrent;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable;
import org.springframework.scheduling.support.TaskUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * {@link org.springframework.beans.factory.FactoryBean} that sets up
 * a {@link java.util.concurrent.ScheduledExecutorService}
 * (by default: a {@link java.util.concurrent.ScheduledThreadPoolExecutor})
 * and exposes it for bean references.
 *
 * <p>Allows for registration of {@link ScheduledExecutorTask ScheduledExecutorTasks},
 * automatically starting the {@link ScheduledExecutorService} on initialization and
 * cancelling it on destruction of the context. In scenarios that only require static
 * registration of tasks at startup, there is no need to access the
 * {@link ScheduledExecutorService} instance itself in application code at all;
 * {@code ScheduledExecutorFactoryBean} is then just being used for lifecycle integration.
 *
 * <p>For an alternative, you may set up a {@link ScheduledThreadPoolExecutor} instance
 * directly using constructor injection, or use a factory method definition that points
 * to the {@link java.util.concurrent.Executors} class.
 * <b>This is strongly recommended in particular for common {@code @Bean} methods in
 * configuration classes, where this {@code FactoryBean} variant would force you to
 * return the {@code FactoryBean} type instead of {@code ScheduledExecutorService}.</b>
 *
 * <p>Note that {@link java.util.concurrent.ScheduledExecutorService}
 * uses a {@link Runnable} instance that is shared between repeated executions,
 * in contrast to Quartz which instantiates a new Job for each execution.
 *
 * <p><b>WARNING:</b> {@link Runnable Runnables} submitted via a native
 * {@link java.util.concurrent.ScheduledExecutorService} are removed from
 * the execution schedule once they throw an exception. If you would prefer
 * to continue execution after such an exception, switch this FactoryBean's
 * {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"}
 * property to "true".
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setPoolSize
 * @see #setRemoveOnCancelPolicy
 * @see #setThreadFactory
 * @see ScheduledExecutorTask
 * @see java.util.concurrent.ScheduledExecutorService
 * @see java.util.concurrent.ScheduledThreadPoolExecutor
 */
/**
 *｛@linkorg.springframework.beans.factory.FactoryBean｝
 *a｛@link java.util.concurrent.ScheduledExecutiorService｝
 *（默认情况下：一个｛@link java.util.concurrent.ScheduledThreadPoolExecutor｝）
 *并为bean引用公开它。
 *
 *＜p＞允许注册｛@link ScheduledExecutiorTask ScheduledExecutitorTasks｝，
 *初始化时自动启动｛@link ScheduledExecutorService｝，并且
 *在破坏上下文的情况下取消它。在只需要静态的场景中
 *在启动时注册任务，无需访问
 *应用程序代码中的{@link ScheduledExecutiorService}实例本身；
 *｛@code-ScheduledExecutiorFactoryBean｝当时正被用于生命周期集成。
 *
 *＜p＞作为替代方案，您可以设置｛@link ScheduledThreadPoolExecutor｝实例
 *直接使用构造函数注入，或者使用指向
 *到{@link java.util.concurrent.Executors}类。
 *<b>强烈建议使用此方法，特别是对于中的常见｛@code@Bean｝方法
 *配置类，其中这个{@codeFactoryBean}变体将强制您
 *返回｛@code FactoryBean｝类型，而不是｛@code-ScheduledExecutiorService｝</b>
 *
 *<p>请注意，｛@link java.util.concurrent.ScheduledExecutiorService｝
 *使用在重复执行之间共享的{@linkRunnable}实例，
 *与Quartz相反，Quartz为每次执行实例化一个新作业。
 *
 *<p><b>警告：</b>通过本机提交的｛@link Runnable Runnables｝
 *｛@link java.util.concurrent.ScheduledExecutiorService｝已从中删除
 *一旦他们抛出异常，执行计划。如果你愿意
 *要在发生此类异常后继续执行，请切换FactoryBean的
 *｛@link#setContinueScheduledExecutionAfterException“continueScheduedExecutionAfter Exception”｝
 *属性设置为“true”。
 *
 *@作者于尔根·霍勒
 *@自2.0起
 *@参见#setPoolSize
 *@参见#setRemoveOnCancelPolicy
 *@参见#setThreadFactory
 *@参见ScheduledExecutiorTask
 *@参见java.util.concurrent.ScheduledExecutiorService
 *@请参阅java.util.concurrent.ScheduledThreadPoolExecutor
 */
@SuppressWarnings("serial")
public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport
		implements FactoryBean<ScheduledExecutorService> {

	private int poolSize = 1;

	@Nullable
	private ScheduledExecutorTask[] scheduledExecutorTasks;

	private boolean removeOnCancelPolicy = false;

	private boolean continueScheduledExecutionAfterException = false;

	private boolean exposeUnconfigurableExecutor = false;

	@Nullable
	private ScheduledExecutorService exposedExecutor;


	/**
	 * Set the ScheduledExecutorService's pool size.
	 * Default is 1.
	 */
	/**
	 *设置ScheduledExecutiorService的池大小。
	 *默认值为1。
	 */
	public void setPoolSize(int poolSize) {
		Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
		this.poolSize = poolSize;
	}

	/**
	 * Register a list of ScheduledExecutorTask objects with the ScheduledExecutorService
	 * that this FactoryBean creates. Depending on each ScheduledExecutorTask's settings,
	 * it will be registered via one of ScheduledExecutorService's schedule methods.
	 * @see java.util.concurrent.ScheduledExecutorService#schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit)
	 * @see java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit)
	 * @see java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit)
	 */
	/**
	 *向ScheduledExecutitorService注册ScheduledExecutiorTask对象的列表
	 *这个FactoryBean创建的。根据每个ScheduledExecutionTask的设置，
	 *它将通过ScheduledExecutiorService的调度方法之一进行注册。
	 *@参见java.util.concurrent.ScheduledExecutiorService#schedule（java.lang.Runnable，long，java.util.conconcurrent.TimeUnit）
	 *@参见java.util.concurrent.ScheduledExecutiorService#scheduleWithFixedDelay（java.lang.Runnable，long，long、java.util.conconcurrent.TimeUnit）
	 *@参见java.util.concurrent.ScheduledExecutiorService#scheduleAtFixedRate（java.lang.Runnable，long，long、java.util.conconcurrent.TimeUnit）
	 */
	public void setScheduledExecutorTasks(ScheduledExecutorTask... scheduledExecutorTasks) {
		this.scheduledExecutorTasks = scheduledExecutorTasks;
	}

	/**
	 * Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor}.
	 * <p>Default is {@code false}. If set to {@code true}, the target executor will be
	 * switched into remove-on-cancel mode (if possible, with a soft fallback otherwise).
	 */
	/**
	 *在｛@link ScheduledThreadPoolExecutor｝上设置取消时删除模式。
	 *＜p＞默认值为｛@code false｝。如果设置为｛@code true｝，则目标执行器将为
	 *切换到取消时删除模式（如果可能，否则使用软回退）。
	 */
	public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) {
		this.removeOnCancelPolicy = removeOnCancelPolicy;
	}

	/**
	 * Specify whether to continue the execution of a scheduled task
	 * after it threw an exception.
	 * <p>Default is "false", matching the native behavior of a
	 * {@link java.util.concurrent.ScheduledExecutorService}.
	 * Switch this flag to "true" for exception-proof execution of each task,
	 * continuing scheduled execution as in the case of successful execution.
	 * @see java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate
	 */
	/**
	 *指定是否继续执行计划任务
	 *在它抛出异常之后。
	 *<p>默认值为“false”，与
	 *｛@link java.util.concurrent.ScheduledExecutiorService｝。
	 *将此标志切换为“true”，以防每个任务的异常执行，
	 *如在成功执行的情况下那样继续预定的执行。
	 *@请参阅java.util.concurrent.ScheduledExecutiorService#scheduleAtFixedRate
	 */
	public void setContinueScheduledExecutionAfterException(boolean continueScheduledExecutionAfterException) {
		this.continueScheduledExecutionAfterException = continueScheduledExecutionAfterException;
	}

	/**
	 * Specify whether this FactoryBean should expose an unconfigurable
	 * decorator for the created executor.
	 * <p>Default is "false", exposing the raw executor as bean reference.
	 * Switch this flag to "true" to strictly prevent clients from
	 * modifying the executor's configuration.
	 * @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService
	 */
	/**
	 *指定此FactoryBean是否应公开
	 *创建的执行器的装饰器。
	 *＜p＞默认值为“false”，将原始执行器公开为bean引用。
	 *将此标志切换为“true”以严格防止客户端
	 *修改执行器的配置。
	 *@请参阅java.util.concurrent.Executors#unconfigurableScheduledExecutorService
	 */
	public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
		this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
	}


	@Override
	protected ExecutorService initializeExecutor(
			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

		ScheduledExecutorService executor =
				createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);

		if (this.removeOnCancelPolicy) {
			if (executor instanceof ScheduledThreadPoolExecutor) {
				((ScheduledThreadPoolExecutor) executor).setRemoveOnCancelPolicy(true);
			}
			else {
				logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
			}
		}

		// Register specified ScheduledExecutorTasks, if necessary.
		// 如有必要，请注册指定的ScheduledExecutiorTasks。
		if (!ObjectUtils.isEmpty(this.scheduledExecutorTasks)) {
			registerTasks(this.scheduledExecutorTasks, executor);
		}

		// Wrap executor with an unconfigurable decorator.
		// 用不可确定的装饰器包装executor。
		this.exposedExecutor = (this.exposeUnconfigurableExecutor ?
				Executors.unconfigurableScheduledExecutorService(executor) : executor);

		return executor;
	}

	/**
	 * Create a new {@link ScheduledExecutorService} instance.
	 * <p>The default implementation creates a {@link ScheduledThreadPoolExecutor}.
	 * Can be overridden in subclasses to provide custom {@link ScheduledExecutorService} instances.
	 * @param poolSize the specified pool size
	 * @param threadFactory the ThreadFactory to use
	 * @param rejectedExecutionHandler the RejectedExecutionHandler to use
	 * @return a new ScheduledExecutorService instance
	 * @see #afterPropertiesSet()
	 * @see java.util.concurrent.ScheduledThreadPoolExecutor
	 */
	/**
	 *创建一个新的｛@link ScheduledExecutiorService｝实例。
	 *＜p＞默认实现创建一个｛@link ScheduledThreadPoolExecutor｝。
	 *可以在子类中重写以提供自定义｛@link ScheduledExecutiorService｝实例。
	 *@param poolSize指定的池大小
	 *@param threadFactory要使用的threadFactory
	 *@param rejectedExecutionHandler要使用的RejectedExecution_Handler
	 *@返回一个新的ScheduledExecutiorService实例
	 *@参见#afterPropertiesSet（）
	 *@请参阅java.util.concurrent.ScheduledThreadPoolExecutor
	 */
	protected ScheduledExecutorService createExecutor(
			int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

		return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler);
	}

	/**
	 * Register the specified {@link ScheduledExecutorTask ScheduledExecutorTasks}
	 * on the given {@link ScheduledExecutorService}.
	 * @param tasks the specified ScheduledExecutorTasks (never empty)
	 * @param executor the ScheduledExecutorService to register the tasks on.
	 */
	/**
	 *注册指定的｛@link ScheduledExecutorTask ScheduledExecutorTasks｝
	 *在给定的｛@link ScheduledExecutiorService｝上。
	 *@param任务指定的ScheduledExecutionTasks（从不为空）
	 *@param executor要在其上注册任务的ScheduledExecutiorService。
	 */
	protected void registerTasks(ScheduledExecutorTask[] tasks, ScheduledExecutorService executor) {
		for (ScheduledExecutorTask task : tasks) {
			Runnable runnable = getRunnableToSchedule(task);
			if (task.isOneTimeTask()) {
				executor.schedule(runnable, task.getDelay(), task.getTimeUnit());
			}
			else {
				if (task.isFixedRate()) {
					executor.scheduleAtFixedRate(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit());
				}
				else {
					executor.scheduleWithFixedDelay(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit());
				}
			}
		}
	}

	/**
	 * Determine the actual Runnable to schedule for the given task.
	 * <p>Wraps the task's Runnable in a
	 * {@link org.springframework.scheduling.support.DelegatingErrorHandlingRunnable}
	 * that will catch and log the Exception. If necessary, it will suppress the
	 * Exception according to the
	 * {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"}
	 * flag.
	 * @param task the ScheduledExecutorTask to schedule
	 * @return the actual Runnable to schedule (may be a decorator)
	 */
	/**
	 *确定要为给定任务安排的实际Runnable。
	 *<p>将任务的Runnable包装在
	 *｛@link org.springframework.scheduling.support.DelegatingErrorHandlingRunnable｝
	 *它将捕获并记录异常。如有必要，它将抑制
	 *根据
	 *｛@link#setContinueScheduledExecutionAfterException“continueScheduedExecutionAfter Exception”｝
	 *旗帜。
	 *@param task要调度的ScheduledExecutorTask
	 *@return实际的Runnable to schedule（可能是一个decorator）
	 */
	protected Runnable getRunnableToSchedule(ScheduledExecutorTask task) {
		return (this.continueScheduledExecutionAfterException ?
				new DelegatingErrorHandlingRunnable(task.getRunnable(), TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER) :
				new DelegatingErrorHandlingRunnable(task.getRunnable(), TaskUtils.LOG_AND_PROPAGATE_ERROR_HANDLER));
	}


	@Override
	@Nullable
	public ScheduledExecutorService getObject() {
		return this.exposedExecutor;
	}

	@Override
	public Class<? extends ScheduledExecutorService> getObjectType() {
		return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ScheduledExecutorService.class);
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

}
